home *** CD-ROM | disk | FTP | other *** search
-
- //Copyright 1991-1992 Roger Bedell All rights reserved
- //See the attached readme file for licensing information.
-
-
- #include "time.h"
- #include "stdlib.h"
- #include "stdio.h"
- #include "string.h"
- #include "io.h"
- #include "grafprnt.hpp"
- #include "graffile.hpp"
- #include "mem.h"
-
- //global printer error flag set to 1 on a printer error
- extern int printer_error_flag;
-
- int check_for_user_input(void); //external function for allowing user abort
-
-
- //Constructor for the base class.
- graphics_file::graphics_file(char * filename)
- {
- //open the file and save its file pointer
- file_ptr = fopen(filename,"rb");
- if(file_ptr == NULL)
- {
- error_message("Could not open .PCX file",NONFATAL);
- }
-
- }
-
- //Constructor for the derived class.
- //pass the filename to the base class constructor
- pcx_graphics_file::pcx_graphics_file(char * filename):graphics_file(filename)
- {
-
- }
-
-
-
- //derived class for pcx file printing
- void pcx_graphics_file::print_file(void)
- {
-
- //in this case its a PCX file
- //read the PCX header and decide on how we are going to approach
- //it (16 or 256 color etc...)
- if(fread((char *)&pcx_header, 1, sizeof(PCX_HEAD), file_ptr) != sizeof(PCX_HEAD))
- {
- //couldnt read the header
- error_message("couldnt read pcx header", NONFATAL);
- return;
- }
- //check for reasonable values in the header
- if(pcx_header.manufacturer != 0x0a)
- {
- error_message("Bad PCX header", NONFATAL);
- return;
- }
-
- //allocate memory for the grey buffer.
- //The grey buffer will hold one line of grey data,
- //one byte per pixel.
- grey_buffer_ptr = mem_malloc(pcx_header.xmax - pcx_header.xmin + 100);
-
- //figure out how to handle it,whether its a 256 or 16 color
- //bitmap
- if(pcx_header.bits_per_pixel == 8)
- {
- //print the body object
- print_256_body();
- }
- else if(pcx_header.bits_per_pixel == 1 && pcx_header.color_planes == 4)
- {
- //print the body object
- print_16_body();
- }
- else
- {
- error_message("Bad PCX header", NONFATAL);
- return;
- }
- mem_free( grey_buffer_ptr);
-
- }
-
-
- //body print for 256 color PCX files
- //Note, this hasn't been fully tested
- void pcx_graphics_file::print_256_body(void)
- {
- //read the palette (256 colors)
- if(read_256_palette() == -1)
- {
- return;
- }
-
- //go to the start of the real data.
- int return_code = fseek(file_ptr, 128L, SEEK_SET);
- if (return_code != 0)
- {
- error_message("Could not seek to image data",NONFATAL);
- return;
- }
-
- long temp = ftell(file_ptr);
-
-
- //create a printer object.
- //get a pointer that will be of the correct printer type
- //pass it the pixels per line so it knows how big to
- //allocate its buffers
-
- printer = graphics_printer::allocate_graphics_printer(pcx_header.bytes_per_line);
-
- //read in each line, expanding the compression,
- //and calculating the grey value from the palette as we go
- //and put the results in the grey buffer.
- int i,j;
- int dup_count;
- int dup_byte;
- int read_byte; //byte read in from the file
- int num_lines = pcx_header.ymax - pcx_header.ymin;
- int depth = pcx_header.ymax - pcx_header.ymin;
- int buffer_count;
-
- char *carry_buffer; //carries stuff from the end of the line to another
- int carry_count = 0;
-
- //carry buffer. Runs cant be longer than 256
- carry_buffer = mem_malloc( 256 );
-
- for( i = 0; i < depth; i++)
- {
- buffer_count = 0; //how far we are in the buffer
-
- //put the stuff left over from the last run into the buffer
- for( j = 0; j < carry_count; j ++)
- {
- grey_buffer_ptr[buffer_count] = carry_buffer[j];
- buffer_count++;
- }
- carry_count = 0;
-
- do //until we've unpacked a line
- {
- //get a byte.
- read_byte = fgetc(file_ptr);
- temp = ftell(file_ptr);
- if(read_byte == EOF)
- {
- error_message("Unexpected end of data", NONFATAL);
- break;
- }
- //trim off any upper stuff left over
- read_byte &= 0xff;
-
- //see if it is a run of bytes indicator (a 0xC0)
- if( (read_byte & 0xc0) == 0xc0 )
- {
- //figure out how many bytes to duplicate
- dup_count = read_byte & 0x3f;
-
- //get the byte to duplicate
- dup_byte = fgetc(file_ptr);
-
- //convert the byte to the proper grey scale value
- dup_byte = grey_convert_256(dup_byte);
-
- //add the dup byte to the output buffer dup_count times
- while(dup_count--)
- {
- if(buffer_count >= pcx_header.bytes_per_line - 1)
- { //overflow of the line buffer. carry it over
- //to the next line
- carry_buffer[carry_count++] = (char)dup_byte;
- }
- else //normal, add to the output buffer
- {
- grey_buffer_ptr[buffer_count++]=(char)dup_byte;
- }
- }
- }
- else //only one byte, convert and save it in the buffer
- {
- read_byte = grey_convert_256(read_byte);
-
- grey_buffer_ptr[buffer_count++] = read_byte;
- }
- } while ( buffer_count < pcx_header.bytes_per_line );
-
- //at the end of each line, send it out to the printer
- printer -> print_grey_line(grey_buffer_ptr, pcx_header.bytes_per_line);
-
- //check the printer error status
- if(printer_error_flag == 1)
- {
- printer_error_flag = 0;
- break;
- }
- //check for user input
- //This allows the user to abort a print in mid-stream
- if(check_for_user_input() == 1)
- {
- break;
- }
-
- }
-
- //deallocate the printer object. Call a pseudo-destructor
- //explicitly to make sure the right one is called (there may
- //be a more elegant way to do this...)
- printer->deallocate_graphics_printer();
- delete printer;
-
- //deallocate carry buffer.
- mem_free(carry_buffer);
-
- }
-
- int pcx_graphics_file::read_256_palette(void)
- {
- //create a temporary rgb palette
- unsigned char temp_palette[768];
-
- //go to the end, then back 769 bytes
- fseek(file_ptr,-769L,SEEK_END);
- long temp2 = ftell(file_ptr);
-
- //make sure the palette is there
- int temp = fgetc(file_ptr);
- temp2 = ftell(file_ptr);
-
- if(temp != 0x0c)
- {
- error_message("Could not read 256 color palette",NONFATAL);
- return -1;
- }
-
- //read the palette into the palette array
- temp = fread(temp_palette, 1, 768, file_ptr);
- temp2 = ftell(file_ptr);
- if(temp != 768)
- {
- error_message("Could not read 256 color palette",NONFATAL);
- return -1;
- }
-
-
- // Convert the RGB values to a grey scale number from 0-255
- //See S.Rimmer, page 386
- int i;
- for( i = 0; i < 256; i++)
- {
- double red = 0.30 * double(temp_palette[i * 3]);
- double green = 0.59 * double(temp_palette[(i * 3) +1]);
- double blue = 0.11 * double(temp_palette[(i * 3) + 2]);
-
- double total = red + green + blue;
-
- unsigned char temp = unsigned char(total);
-
- palette_256[i] = temp;
-
- }
-
- return 0;
-
- }
-
-
- //now, a little contrast needs to be added via a lookup
- //table (Rimmer P388) to get a better looking image
- unsigned char greymap[256] =
- {
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
- 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
-
- 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
- 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
-
- 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21,
- 0x22, 0x23, 0x23, 0x24, 0x25, 0x27, 0x27, 0x28,
-
- 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-
- 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
- 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
-
- 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
- 0x50, 0x51, 0x52, 0x53, 0x55, 0x56, 0x57, 0x58,
-
- 0x59, 0x5a, 0x5b, 0x5d, 0x5e, 0x5f, 0x60, 0x61,
- 0x63, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6a, 0x6b,
-
- 0x6c, 0x6e, 0x70, 0x72, 0x73, 0x74, 0x76, 0x78,
- 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88,
-
- 0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x98, 0x9a,
- 0x9c, 0x9f, 0xa1, 0xa4, 0xa6, 0xa9, 0xab, 0xae,
-
- 0xb0, 0xb2, 0xb3, 0xb5, 0xb7, 0xb9, 0xba, 0xbc,
- 0xbd, 0xbe, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca,
-
- 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd9, 0xdb,
- 0xdd, 0xe0, 0xe3, 0xe6, 0xe8, 0xeb, 0xed, 0xef,
-
- 0xf2, 0xf5, 0xf8, 0xfb, 0xfe, 0xfe, 0xfe, 0xfe,
- 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
-
- 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
- 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
-
- 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
- 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe
-
- };
-
-
- int pcx_graphics_file::grey_convert_256(int convert_char)
- {
- //the input is an index into the palette
- //we just need to convert it to a grey scale value
-
- unsigned char grey_value = palette_256[convert_char];
-
- //brighten it up a little
- int temp = grey_value + 30;
- if(temp > 255)
- {
- temp = 255;
- }
- grey_value = char(temp);
-
-
- //substitute the lookup grey value for the one derived from
- //the palette
-
- return greymap[grey_value];
-
- }
-
-
-
- //body print for 16 color PCX files
- //These are in planes, a little different to decode and transform
- void pcx_graphics_file::print_16_body(void)
- {
- //read the palette (16 colors)
- if(read_16_palette() == -1)
- {
- return;
- }
-
- //we should be already at the start of the data
- long temp = ftell(file_ptr);
-
-
- //create a printer object.
- //get a pointer that will be of the correct printer type
- //pass it the pixels per line so it knows how big to
- //allocate its buffers
- pixels_per_line = pcx_header.xmax - pcx_header.xmin;
-
- printer = graphics_printer::allocate_graphics_printer(pixels_per_line);
-
- //read in each line, expanding the compression,
- //4 color pcx files are a little weird, the first line
- //has the msbit of the palette index, the fourth line has
- //the lsbit of the palett index etc So we need to read in
- //four lines at a time, then convert to a grey line to
- //output to the printer object
- //and put the results in the grey buffer.
- int i,j;
- int dup_count;
- int dup_byte;
- int read_byte; //byte read in from the file
- int num_lines = pcx_header.ymax - pcx_header.ymin;
- int depth = pcx_header.ymax - pcx_header.ymin;
- int buffer_count = 0;
- int temp_line_count = 0;
- char *temp_buffer[4]; //temporarily keeps the four lines
- char *carry_buffer; //carries stuff from the end of the line to another
- int carry_count = 0;
-
-
- FILE * testfile = fopen("testout.out","w");
-
- //allocate room for the temp buffers
- for(i = 0; i < 4; i++)
- {
- temp_buffer[i] = mem_malloc( pcx_header.bytes_per_line + 256);
- }
- //carry buffer. Runs cant be longer than 256
- carry_buffer = mem_malloc( 256 );
-
- for( i = 0; i < depth; i++)
- {
-
- //do four lines at a time (four planes)
- for(temp_line_count = 0; temp_line_count < 4; temp_line_count++)
- {
- buffer_count = 0;
-
- //put the stuff left over from the last run into the buffer
- for( j = 0; j < carry_count; j ++)
- {
- temp_buffer[temp_line_count][buffer_count] = carry_buffer[j];
- buffer_count++;
- }
- carry_count = 0;
-
- do //until we've unpacked a line
- {
- //get a byte.
- read_byte = fgetc(file_ptr);
- temp = ftell(file_ptr);
-
-
- if(read_byte == EOF)
- {
- error_message("Unexpected end of data", NONFATAL);
- break;
- }
- //trim off any upper stuff left over
- read_byte &= 0xff;
-
- //see if it is a run of bytes indicator (a 0xC0)
- if( (read_byte & 0xc0) == 0xc0 )
- {
- //figure out how many bytes to duplicate
- dup_count = read_byte & 0x3f;
-
- //get the byte to duplicate
- dup_byte = fgetc(file_ptr);
-
- //add the dup byte to the output buffer dup_count times
- while(dup_count--)
- {
- if(buffer_count >= pcx_header.bytes_per_line -1 )
- { //overflow of the line buffer. carry it over
- //to the next line
- carry_buffer[carry_count++] = (char)dup_byte;
- }
- else //normal, add to the output buffer
- {
- temp_buffer[temp_line_count][buffer_count++]=
- (char)dup_byte;
- }
- }
- }
- else //only one byte, convert and save it in the buffer
- {
- temp_buffer[temp_line_count][buffer_count++]=(char)read_byte;
- }
-
- } while ( buffer_count < pcx_header.bytes_per_line );
-
-
- }//end for
-
- //convert the 4 plane lines to one grey line
- grey_convert_16(temp_buffer);
-
-
- //at the end of each line, send it out to the printer
- printer -> print_grey_line(grey_buffer_ptr, pixels_per_line);
-
- //check the printer error status
- if(printer_error_flag == 1)
- {
- printer_error_flag = 0;
- break;
- }
-
- //check for user input
- //This allows the user to abort a print in mid-stream
- if(check_for_user_input() == 1)
- {
- break;
- }
-
-
- }
-
- //deallocate the printer object. Call a pseudo-destructor
- //explicitly to make sure the right one is called (there may
- //be a more elegant way to do this...)
- printer->deallocate_graphics_printer();
- delete printer;
-
- //deallocate room for the temp buffers
- for(i = 0; i < 4; i++)
- {
- mem_free(temp_buffer[i]);
- }
- //deallocate carry buffer.
- mem_free(carry_buffer);
-
- }
-
- //converts the 4 plane lines to one grey line
- int pcx_graphics_file::grey_convert_16(char * temp_buffer[4])
- {
- int temp_palette_index = 0;
-
- for(int i = 0; i < pixels_per_line; i++)
- {
- temp_palette_index = 0;
-
- for(int j = 0; j < 4; j ++)
- {
- //which bit?
- int bit_in_byte = 0x80 >> (i % 8 );
- int byte_num = i / 8;
-
- //construct a palette index from the bits in each plane
- //get the bit and put it in the temp palette index
-
- //see if its a one or a zero
- if(bit_in_byte & temp_buffer[j][byte_num])
- { //its a one
- temp_palette_index |= 1 << j;
- }
- //else its a zero, so do nothing.
-
- }
-
- //so now we have the palette index, look up the grey palette
- //and assign a grey 8 bit value to it and stick it in
- //the grey buffer.
-
- int temp_int = palette_16[temp_palette_index];
- if(temp_int > 255)
- {
- temp_int = 255;
- }
-
- grey_buffer_ptr[i] = temp_int;
-
-
- }
- return 0;
-
- }
-
- //doesnt actually read anything, but sets up the
- //grey 16 color palette
- int pcx_graphics_file::read_16_palette(void)
- {
-
- // Convert the RGB values to a grey scale number from 0-255
- //See S.Rimmer, page 386
- int i;
- for( i = 0; i < 16; i++)
- {
- double red = 0.30 * double(pcx_header.palette[i * 3]);
- double green = 0.59 * double(pcx_header.palette[(i * 3) +1]);
- double blue = 0.11 * double(pcx_header.palette[(i * 3) + 2]);
-
- double total = red + green + blue;
-
- unsigned char temp = unsigned char(total);
-
- palette_16[i] = temp;
-
- }
-
- return 0;
-
-
- }
-